/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = sip_req.c                                          */
/*  NOTE      =                                                    */
/*  DATE      = 2015/07/08 by songbb                               */
/*******************************************************************/

#include <iconv2utf8.h>
#include "conntrack.h"
#include "frct_comm.h"
#include "frreport_comm.h"

#include "sip_core.h"
#include "sip_comm.h"
#include "sip_req.h"
#include "sip_sdp.h"

#define SIP_TIMEOUT   5 * 60   //单位秒
struct timeval g_st_time;

/*******************************************************************************
*  FUNC     :  检查是否超时
*  ARGS     :  p_node           当前节点
*           :  p_data
*  RTN      :  1   (成功)
*  NOTE     :
*******************************************************************************/
FR_STATIC int __ct_check_timeout(Frlist_node* p_node, const void *p_data)
{
    L7_sip_stmt *p_st_stmt = NULL;
    Frhash_header *p_hash_stmt = (Frhash_header *)p_data;

    p_st_stmt = (L7_sip_stmt *)p_node->data;

    if (p_st_stmt->st_req_end_timestamp.tv_sec + SIP_TIMEOUT <= g_st_time.tv_sec)
    {
        frhash2_del(p_hash_stmt, p_node, sip_stmt_node_free);
        return 1;
    }

    return 1;
}

/*******************************************************************************
*  FUNC     :  清除hash中超时的node
*  ARGS     :  p_hash_stmt                          (hash)
*  ARGS     :  st_timestamp                         (当前时间)
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void __sip_clear_timeout_stmt(L7session_sip_private *p_st_sess
                                      , Frhash_header *p_hash_stmt
                                      , struct timeval st_timestamp)
{
    if (p_st_sess->st_timestamp.tv_sec == 0)
    {
        p_st_sess->st_timestamp = st_timestamp;
        return;
    }
    else if (p_st_sess->st_timestamp.tv_sec + SIP_TIMEOUT > st_timestamp.tv_sec)
    {
        return;
    }
    else
    {
        p_st_sess->st_timestamp = st_timestamp;
    }

    g_st_time = st_timestamp;
    frhash2_run(p_hash_stmt, p_hash_stmt, __ct_check_timeout);

    return;
}

int __sip_get_uri_user(char *p_uri
                    , char **pp_uri_user)
{
    char *p_pos = NULL;
    char *p_uri_user = NULL;
    unsigned long ul_uri_user_len;
    char *p_pos_at = NULL;

    if (p_uri == NULL)
        goto error;

    if ((p_pos = strstr(p_uri, "sip:")) == NULL)
        goto error;

    if ((p_pos_at = strchr(p_uri, '@')) != NULL)
        ul_uri_user_len = p_pos_at - p_pos - strlen("sip:");
    else
        ul_uri_user_len = strlen(p_uri) - strlen("sip:");

    if (ul_uri_user_len <= 0)
        goto error;

    if ((p_uri_user = (char *) frmalloc(sizeof(char) * (ul_uri_user_len + 1))) == NULL)
    {
        SIP_MALLOCK_ERR;
        goto error;
    }
    memcpy(p_uri_user, p_pos + strlen("sip:"), ul_uri_user_len);
    p_uri_user[ul_uri_user_len] = '\0';

    *pp_uri_user = p_uri_user;
    p_uri_user = NULL;

    SIP_PRINT_CRIT("Request-URI User Part:[%s]\n", *pp_uri_user);

    return FR_SUCC;
error:
    sip_free((void **) &p_uri_user);
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  如果域值名是缩写形式，则转换成完整形式
*  ARGS     :  **pp_field_name                          (域值名)
*  RTN      :
*  NOTE     :
*******************************************************************************/
void __sip_convert_abbr_field_name(char **pp_field_name)
{
    if (pp_field_name == NULL || *pp_field_name == NULL)
        return;

    if (strcasecmp(*pp_field_name, "i") == 0)
    {
        sip_free((void **) pp_field_name);
        *pp_field_name = frstrdup("Call-ID");
    }
    else if (strcasecmp(*pp_field_name, "m") == 0)
    {
        sip_free((void **) pp_field_name);
        *pp_field_name = frstrdup("Contact");
    }
    else if (strcasecmp(*pp_field_name, "e") == 0)
    {
        sip_free((void **) pp_field_name);
        *pp_field_name = frstrdup("Content-Encoding");
    }
    else if (strcasecmp(*pp_field_name, "l") == 0)
    {
        sip_free((void **) pp_field_name);
        *pp_field_name = frstrdup("Content-Length");
    }
    else if (strcasecmp(*pp_field_name, "c") == 0)
    {
        sip_free((void **) pp_field_name);
        *pp_field_name = frstrdup("Content-Type");
    }
    else if (strcasecmp(*pp_field_name, "f") == 0)
    {
        sip_free((void **) pp_field_name);
        *pp_field_name = frstrdup("From");
    }
    else if (strcasecmp(*pp_field_name, "s") == 0)
    {
        sip_free((void **) pp_field_name);
        *pp_field_name = frstrdup("Subject");
    }
    else if (strcasecmp(*pp_field_name, "k") == 0)
    {
        sip_free((void **) pp_field_name);
        *pp_field_name = frstrdup("Supported");
    }
    else if (strcasecmp(*pp_field_name, "t") == 0)
    {
        sip_free((void **) pp_field_name);
        *pp_field_name = frstrdup("To");
    }
    else if (strcasecmp(*pp_field_name, "v") == 0)
    {
        sip_free((void **) pp_field_name);
        *pp_field_name = frstrdup("Via");
    }
}

/*******************************************************************************
*  FUNC     :  解析SIP请求
*  ARGS     :  *p_st_conn                               (ct信息)
*           :  *p_st_sess                               (SIP私有的session)
*           :  *p_st_sip_packet                         (SIP数据包)
*           :  *p_st_hash_report                        (数据上报)
*  RTN      :  0                                        (FR_SUCC)
*              1                                        (FR_FAIL)
*  NOTE     :
*******************************************************************************/
int __sip_unpack_req(Conntrack *p_st_conn
                    , L7session_sip *p_st_sess
                    , L7_sip_packet *p_st_sip_packet
                    , Frhash_header *p_st_hash_report
                    , Apm_packet *p_analyze_in)
{
    L7_session *p_st_session = frct_get_session(p_st_conn);
    L7session_sip_private *p_st_session_private = (L7session_sip_private *) frct_get_session_private(p_st_session);
    Frhash_header *p_hash_stmt = p_st_session_private->p_hash_stmt;
    int i_pos_eoh = 0;
    int i_pos_uri = 0;
    int i_pos_uri_len = 0;
    int i_title_len = 0;
    char *p_title = NULL;
    int i_pos_header_fields = 0;
    int i_pos_colon = 0;
    char *p_field_name = NULL;
    char *p_field_value = NULL;
    char *p_field_value2 = NULL;
    char *p_field_value_whole = NULL;
    int i_pos_line_end = 0;
    uint8_t tmp;
    int i_append_first_value;
    Frstr *p_frstr = NULL;
    int i_expires = 0;
    int i_save_content_body = FR_NO;
    char *p_content_body = NULL;
    int i_content_len = 0;
    Frreport_body_data *p_st_body = NULL;
    char *p_report_key = NULL;
    int i_report_key_len = 0;
    int i_dissect_sdp = FR_NO;
    char *p_pos_username = NULL;
    char *p_pos_username_end = NULL;
    char *p_username = NULL;
    unsigned long ul_username_len = 0L;
    char *p_branch = NULL;
    L7_sip_stmt *p_st_sip_stmt = NULL;
    Frlist_node *p_st_node = NULL;
    char *p_uri = NULL;
    char *p_uri_user = NULL;

    char *p_body_utf8 = NULL;
    unsigned int ui_body_utf8_len = 0;

    if (frcap_set_cs_srv(p_st_conn, p_analyze_in->dst_ip, p_analyze_in->dst_port) != FR_SUCC)
        goto error;

    if ((p_st_body = frreport_body_new_l7(p_st_conn)) == NULL)
        goto error;

    // 查找CRLFCRLF
    if (bytebuff_memstr(p_st_sip_packet->p_st_packet, 0, bytebuff_length(p_st_sip_packet->p_st_packet), APM_SIP_EOH, (int) strlen(APM_SIP_EOH), &i_pos_eoh) != FR_SUCC)
        goto error;

    // 查找first line的uri起始位置
    if (bytebuff_memstr(p_st_sip_packet->p_st_packet, 0, i_pos_eoh + (int) strlen(APM_SIP_EOH), APM_SIP_SP, (int) strlen(APM_SIP_SP), &i_pos_uri) != FR_SUCC)
        goto error;
    i_pos_uri += strlen(APM_SIP_SP);

    // 查找first line的uri结束位置
    if (bytebuff_memstr(p_st_sip_packet->p_st_packet, i_pos_uri, i_pos_eoh + (int) strlen(APM_SIP_EOH), APM_SIP_SP, (int) strlen(APM_SIP_SP), &i_pos_uri_len) != FR_SUCC)
        goto error;
    i_pos_uri_len -= i_pos_uri;

    if ((p_uri = (char *) frmalloc(sizeof(char) * (i_pos_uri_len + 1))) == NULL)
    {
        SIP_MALLOCK_ERR;
        goto error;
    }
    if (bytebuff_get_bytes_at(p_st_sip_packet->p_st_packet, i_pos_uri, (unsigned int) (i_pos_uri_len), p_uri) != FR_SUCC)
        goto error;
    p_uri[i_pos_uri_len] = '\0';
    SIP_PRINT_WARN("p_uri:[%s]\n", p_uri);

    i_title_len = i_pos_uri + i_pos_uri_len;
    if ((p_title = (char *) frmalloc(sizeof(char) * (i_title_len + 1))) == NULL)
    {
        SIP_MALLOCK_ERR;
        goto error;
    }
    if (bytebuff_get_bytes_at(p_st_sip_packet->p_st_packet, 0, (unsigned int) (i_title_len), p_title) != FR_SUCC)
        goto error;
    p_title[i_title_len] = '\0';
    SIP_PRINT_WARN("p_title:[%s]\n", p_title);

    // 确定header fields的起始行位置
    if (bytebuff_memstr(p_st_sip_packet->p_st_packet, 0, i_pos_eoh + (int) strlen(APM_SIP_EOH), APM_SIP_EOL, (int) strlen(APM_SIP_EOL), &i_pos_header_fields) != FR_SUCC)
        goto error;
    i_pos_header_fields += strlen(APM_SIP_EOL);

    while (i_pos_header_fields < i_pos_eoh)
    {
        // 查找头域分隔符:的位置
        if (bytebuff_memstr(p_st_sip_packet->p_st_packet, i_pos_header_fields, i_pos_eoh + (int) strlen(APM_SIP_EOH), APM_SIP_COLON, (int) strlen(APM_SIP_COLON), &i_pos_colon) != FR_SUCC)
            goto error;
        i_pos_colon -= i_pos_header_fields;
        if (i_pos_colon == 0)
            goto error;
        i_pos_colon += i_pos_header_fields;
        // 取field name值
        if ((p_field_name = (char *) frmalloc(sizeof(char) * (i_pos_colon - i_pos_header_fields + 1))) == NULL)
        {
            SIP_MALLOCK_ERR;
            goto error;
        }
        if (bytebuff_get_bytes_at(p_st_sip_packet->p_st_packet, i_pos_header_fields, (unsigned int) (i_pos_colon - i_pos_header_fields), p_field_name) != FR_SUCC)
            goto error;
        p_field_name[i_pos_colon - i_pos_header_fields] = '\0';
        frtrim(p_field_name);
        __sip_convert_abbr_field_name(&p_field_name);
        SIP_PRINT_WARN("p_field_name:[%s]\n", p_field_name);
        i_append_first_value = FR_NO;

        // 查找当前行的结束位置
        if (bytebuff_memstr(p_st_sip_packet->p_st_packet, i_pos_colon, i_pos_eoh + (int) strlen(APM_SIP_EOH), APM_SIP_EOL, (int) strlen(APM_SIP_EOL), &i_pos_line_end) != FR_SUCC)
            goto error;
        i_pos_line_end -= i_pos_colon;
        if (i_pos_line_end == 0)
            goto error;
        i_pos_line_end += i_pos_colon;

        // 取field value值
        if ((p_field_value = (char *) frmalloc(sizeof(char) * (i_pos_line_end - i_pos_colon - 1 + 1))) == NULL)
        {
            SIP_MALLOCK_ERR;
            goto error;
        }
        if (bytebuff_get_bytes_at(p_st_sip_packet->p_st_packet, i_pos_colon + 1, (unsigned int) (i_pos_line_end - i_pos_colon - 1), p_field_value) != FR_SUCC)
            goto error;
        p_field_value[i_pos_line_end - i_pos_colon - 1] = '\0';
        frtrim(p_field_value);

        i_pos_header_fields = (int) (i_pos_line_end + strlen(APM_SIP_EOL));

        if (i_pos_header_fields < i_pos_eoh)
        {
            if (bytebuffer_get_at(p_st_sip_packet->p_st_packet, i_pos_header_fields, &tmp) != FR_SUCC)
                goto error;
            while (tmp == ' ' || tmp == '\t') // 多行field value
            {
                // 查找当前行的结束位置
                if (bytebuff_memstr(p_st_sip_packet->p_st_packet, i_pos_header_fields, i_pos_eoh + (int) strlen(APM_SIP_EOH), APM_SIP_EOL, (int) strlen(APM_SIP_EOL), &i_pos_line_end) != FR_SUCC)
                    goto error;
                i_pos_line_end -= i_pos_header_fields;
                if (i_pos_line_end == 0)
                    goto error;
                i_pos_line_end += i_pos_header_fields;

                // 先插入第一个value
                if (i_append_first_value == FR_NO)
                {
                    if ((p_frstr = frstr_new(64)) == NULL)
                        goto error;
                    if (frstr_append(p_frstr, p_field_value, (int) strlen(p_field_value)) != FR_SUCC)
                        goto error;
                    sip_free((void **) &p_field_value);
                    i_append_first_value = FR_YES;
                }

                // 取field value值
                if ((p_field_value2 = (char *) frmalloc(sizeof(char) * (i_pos_line_end - i_pos_header_fields + 1))) == NULL)
                {
                    SIP_MALLOCK_ERR;
                    goto error;
                }
                if (bytebuff_get_bytes_at(p_st_sip_packet->p_st_packet, i_pos_header_fields, (unsigned int) (i_pos_line_end - i_pos_header_fields), p_field_value2) != FR_SUCC)
                    goto error;
                p_field_value2[i_pos_line_end - i_pos_header_fields] = '\0';
                frtrim(p_field_value2);
                if (frstr_append(p_frstr, " ,", 2) != FR_SUCC)
                    goto error;
                if (frstr_append(p_frstr, p_field_value2, (int) strlen(p_field_value2)) != FR_SUCC)
                    goto error;
                sip_free((void **) &p_field_value2);

                i_pos_header_fields = (int) (i_pos_line_end + strlen(APM_SIP_EOL));

                if (i_pos_header_fields >= i_pos_eoh)
                    break;
                if (bytebuffer_get_at(p_st_sip_packet->p_st_packet, i_pos_header_fields, &tmp) != FR_SUCC)
                    goto error;
            }
        }

        if (i_append_first_value == FR_YES)
            p_field_value_whole = frstr_free2(&p_frstr);
        else
        {
            p_field_value_whole = p_field_value;
            p_field_value = NULL;
        }
        SIP_PRINT_WARN("p_field_value_whole:[%s]\n", p_field_value_whole);

        if (p_st_sip_packet->em_req_method == SIP_METHOD_TYPE_REGISTER)
        {
            if (strcasecmp(p_field_name, "Expires") == 0)
                i_expires = atoi(p_field_value_whole);
            else if (strcasecmp(p_field_name, "Authorization") == 0)
            {
                if ((p_pos_username = strstr(p_field_value_whole, APM_SIP_USERNAME_TAG)) != NULL &&
                    (p_pos_username_end = strstr(p_pos_username + strlen(APM_SIP_USERNAME_TAG), "\"")) != NULL)
                {
                    ul_username_len = p_pos_username_end - (p_pos_username + strlen(APM_SIP_USERNAME_TAG));
                    if ((p_username = (char *) frmalloc(sizeof(char) * ul_username_len + 1)) == NULL)
                    {
                        SIP_MALLOCK_ERR;
                        goto error;
                    }
                    memcpy(p_username, p_pos_username + strlen(APM_SIP_USERNAME_TAG), ul_username_len);
                    p_username[ul_username_len] = '\0';
                    SIP_PRINT_ALERT("p_username:[%s]\n", p_username);
                }
            }
        }
        else if (p_st_sip_packet->em_req_method == SIP_METHOD_TYPE_MESSAGE || p_st_sip_packet->em_req_method == SIP_METHOD_TYPE_NOTIFY)
        {
            if (strcasecmp(p_field_name, "Content-Type") == 0 &&
                    (strcasecmp(p_field_value_whole, "text/plain") == 0 ||
                    strcasecmp(p_field_value_whole, "Application/MANSCDP+xml") == 0))
                i_save_content_body = FR_YES;
        }
        else if (p_st_sip_packet->em_req_method == SIP_METHOD_TYPE_INVITE)
        {
            if (strcasecmp(p_field_name, "Content-Type") == 0 && strcasecmp(p_field_value_whole, "application/sdp") == 0)
                i_dissect_sdp = FR_YES;
        }

        // 过滤敏感字段
        if (strcasecmp(p_field_name, "Authorization") == 0 ||
                strcasecmp(p_field_name, "Proxy-Authorization") == 0 ||
                strcasecmp(p_field_name, "Proxy-Authenticate") == 0 ||
                strcasecmp(p_field_name, "WWW-Authenticate") == 0)
        {
            sip_free((void **) &p_field_name);
            sip_free((void **) &p_field_value_whole);
            continue;
        }

        if (frstrlower(p_field_name, (int) strlen(p_field_name)) != FR_SUCC)
            goto error;
        i_report_key_len = (int) (strlen(APM_SIP_REPORT_REQ_HDR_PREFIX) + strlen(p_field_name) + 1);
        if ((p_report_key = (char *) frmalloc(sizeof(char) * i_report_key_len)) == NULL)
        {
            SIP_MALLOCK_ERR;
            goto error;
        }
        snprintf(p_report_key, (size_t) i_report_key_len, APM_SIP_REPORT_REQ_HDR_PREFIX"%s", p_field_name);
        if (frreport_body_l7_add_str(p_st_body, p_report_key, p_field_value_whole) != FR_SUCC)
            goto error;

        /**
         * XXX: 有可能会同时存在多个Via头,每经过一个sip节点时,会在前面增加一个Via头,所以取第1个Via的branch值做hash存储
         */
        if (strcasecmp(p_field_name, "Via") == 0 && p_branch == NULL)
        {
            if (sip_get_branch_from_via(p_field_value_whole, &p_branch) != FR_SUCC)
                goto error;
            // 为确保不重复,先删除
            frhash2_delStr(p_hash_stmt, p_branch, (unsigned int) strlen(p_branch), sip_stmt_node_free);
        }

        sip_free((void **) &p_field_name);
        sip_free((void **) &p_field_value_whole);
        sip_free((void **) &p_report_key);
    }

    if (p_branch == NULL)
    {
        SIP_PRINT_CRIT("NO branch!\n");
        goto error;
    }

    if ((p_st_sip_stmt = (L7_sip_stmt *) frmalloc(sizeof(L7_sip_stmt))) == NULL)
    {
        SIP_MALLOCK_ERR;
        goto error;
    }
    memset(p_st_sip_stmt, 0x00, sizeof(L7_sip_stmt));

    if (i_save_content_body == FR_YES &&
            p_st_sip_packet->ui_content_length > 0 &&
            bytebuff_length(p_st_sip_packet->p_st_packet) - i_pos_eoh - strlen(APM_SIP_EOH) > 0)
    {
        i_content_len = (int) (bytebuff_length(p_st_sip_packet->p_st_packet) - i_pos_eoh - strlen(APM_SIP_EOH));
        if ((p_content_body = (char *) frmalloc(sizeof(char) * (i_content_len + 1))) == NULL)
        {
            SIP_MALLOCK_ERR;
            goto error;
        }
        if (bytebuff_get_bytes_at(p_st_sip_packet->p_st_packet, (int) (i_pos_eoh + strlen(APM_SIP_EOH)), (unsigned int) (i_content_len), p_content_body) != FR_SUCC)
            goto error;
        p_content_body[i_content_len] = '\0';

        if (iconv_to_utf8(p_content_body, i_content_len, "gb2312", &p_body_utf8, &ui_body_utf8_len) != FR_SUCC)
            goto error;

        if (frreport_body_l7_add_str(p_st_body, APM_SIP_REPORT_REQ_BODY, p_body_utf8) != FR_SUCC)
            goto error;

        sip_free((void **) &p_body_utf8);
        sip_free((void **) &p_content_body);
    }

    // 分析SDP协议
    if (i_dissect_sdp == FR_YES &&
        p_st_sip_packet->ui_content_length > 0 &&
        bytebuff_length(p_st_sip_packet->p_st_packet) - i_pos_eoh - strlen(APM_SIP_EOH) > 0)
    {
        i_content_len = (int) (bytebuff_length(p_st_sip_packet->p_st_packet) - i_pos_eoh - strlen(APM_SIP_EOH));
        if ((p_content_body = (char *) frmalloc(sizeof(char) * i_content_len + 1)) == NULL)
        {
            SIP_MALLOCK_ERR;
            goto error;
        }
        if (bytebuff_get_bytes_at(p_st_sip_packet->p_st_packet, (int) (i_pos_eoh + strlen(APM_SIP_EOH)), (unsigned int) (i_content_len), p_content_body) != FR_SUCC)
            goto error;
        p_content_body[i_content_len] = '\0';
        if (sip_dissect_sdp(p_st_sip_stmt, p_content_body, i_content_len, FR_YES) != FR_SUCC)
            goto error;
        if (frreport_body_l7_add_str(p_st_body, APM_SIP_REPORT_REQ_BODY, p_content_body) != FR_SUCC)
            goto error;
        sip_free((void **) &p_content_body);
    }

    if (p_st_sip_packet->em_req_method == SIP_METHOD_TYPE_INVITE)
    {
        p_st_sip_stmt->ul_invite_begin_timestamp = sip_get_timestamp(&(p_st_sip_packet->st_timestamp_first));
    }
    else if (p_st_sip_packet->em_req_method == SIP_METHOD_TYPE_REGISTER)
    {
        // Expires字段不为0时为注册、更新等操作，为0时表示注销
        if (i_expires != 0)
        {
            if (p_username && p_st_sip_stmt)
            {
                p_st_sip_stmt->i_is_register = FR_YES;
                p_st_sip_stmt->em_req_method = p_st_sip_packet->em_req_method;
            }
        }
        else if (p_st_sip_stmt)
            p_st_sip_stmt->i_is_register = FR_NO;

//        sip_free_stmt(&p_st_sip_stmt);
//        frreport_body_free(&p_st_body);
//        goto success;
    }
//    else if (p_st_sip_packet->em_req_method == SIP_METHOD_TYPE_BYE && p_st_sip_stmt)
//    {
//        p_st_sip_stmt->em_req_method = p_st_sip_packet->em_req_method;
//        frreport_body_free(&p_st_body);
//        sip_free_stmt(&p_st_sip_stmt);
//        goto success;
//    }

    if (frreport_body_l7_add_str(p_st_body, APM_REPORT_KEY_SESSION_ID, p_st_session->arr_session_id) != FR_SUCC)
        goto error;
    if (p_username != NULL)
    {
        if (frreport_body_l7_add_str(p_st_body, APM_REPORT_KEY_SESSION_USERNAME, p_username) != FR_SUCC)
            goto error;
    }
    if (p_st_sess->st_registered_timestamp.tv_sec != 0L || p_st_sess->st_registered_timestamp.tv_usec != 0L)
    {
        if (frreport_body_l7_add_timeval(p_st_body, APM_REPORT_KEY_SESSION_LOGIN_TIMESTAMP, &(p_st_sess->st_registered_timestamp)) != FR_SUCC)
            goto error;
    }
    if (p_st_sess->p_server != NULL)
    {
        if (frreport_body_l7_add_str(p_st_body, APM_REPORT_KEY_SESSION_SERVER, p_st_sess->p_server) != FR_SUCC)
            goto error;
    }
    if (frreport_body_l7_add_str(p_st_body, APM_REPORT_KEY_TRANS_TITLE, p_title) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_connInfo(p_st_body, p_st_conn) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_ulong(p_st_body, APM_REPORT_KEY_REQ_ID, frct_seq_increase(p_st_conn)) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_int(p_st_body, APM_REPORT_KEY_REQ_ISRESPREQUIRED, p_st_sip_packet->em_req_method==SIP_METHOD_TYPE_ACK ? FR_NO : FR_YES) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_timeval(p_st_body, APM_REPORT_KEY_REQ_START_TIMESTAMP, &(p_st_sip_packet->st_timestamp_first)) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_timeval(p_st_body, APM_REPORT_KEY_REQ_END_TIMESTAMP, &(p_st_sip_packet->st_timestamp_last)) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_long(p_st_body, APM_REPORT_KEY_REQ_SEND_TIME_US, frtime_diff(&(p_st_sip_packet->st_timestamp_first), &(p_st_sip_packet->st_timestamp_last))) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_ulong(p_st_body, APM_REPORT_KEY_REQ_DATA_BYTES, p_st_sip_packet->ui_length) != FR_SUCC)
        goto error;

    if (p_st_sip_packet->em_req_method == SIP_METHOD_TYPE_INVITE)
    {
        if (__sip_get_uri_user(p_uri, &p_uri_user) == FR_SUCC)
        {
            if (frreport_body_l7_add_str(p_st_body, APM_SIP_REPORT_REQ_URI_USER, p_uri_user) != FR_SUCC)
                goto error;
            sip_free((void **) &p_uri_user);
        }
    }

    frreport_body_l7list_free(&(p_st_sip_stmt->p_report_comm));
    p_st_sip_stmt->p_report_comm = FRREPORT_BODY_L7LIST_CLONE_COMM(p_st_body);

    if (frreport_body_l7_add_str(p_st_body, APM_SIP_REPORT_REQ_URI, p_uri) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_str(p_st_body, APM_SIP_REPORT_REQ_METHOD, p_st_sip_packet->p_req_method) != FR_SUCC)
        goto error;

    frreport_body_l7list_free(&(p_st_sip_stmt->p_report_req));
    p_st_sip_stmt->p_report_req = FRREPORT_BODY_L7LIST_CLONE_REQ(p_st_body);

    if (sip_report_data(p_st_conn, FR_YES, p_st_body, p_st_hash_report) != FR_SUCC)
        goto error;

    p_st_sip_stmt->st_req_end_timestamp.tv_sec = p_st_sip_packet->st_timestamp_last.tv_sec;
    p_st_sip_stmt->st_req_end_timestamp.tv_usec = p_st_sip_packet->st_timestamp_last.tv_usec;
    p_st_sip_stmt->em_req_method = p_st_sip_packet->em_req_method;
    sip_free((void **) &(p_st_sip_stmt->p_username));
    p_st_sip_stmt->p_username = p_username;
    p_username = NULL;
    sip_free((void **) &(p_st_sip_stmt->p_uri));
    p_st_sip_stmt->p_uri = p_uri;
    p_uri = NULL;
    p_st_node = frlist_node_create(p_st_sip_stmt);
    if (frhash2_addStr(p_hash_stmt, p_branch, (unsigned int) strlen(p_branch), p_st_node) != FR_SUCC)
        goto error;
    p_st_sip_stmt = NULL;

    __sip_clear_timeout_stmt(p_st_session_private, p_hash_stmt, p_st_sip_packet->st_timestamp_last);

    sip_free((void **) &p_branch);
    sip_free((void **) &p_title);
    return FR_SUCC;
error:
    sip_free((void **) &p_body_utf8);
    sip_free_stmt(&p_st_sip_stmt);
    sip_stmt_node_free(p_st_node);
    sip_free((void **) &p_branch);
    sip_free((void **) &p_title);
    sip_free((void **) &p_field_name);
    sip_free((void **) &p_report_key);
    sip_free((void **) &p_field_value);
    sip_free((void **) &p_field_value_whole);
    sip_free((void **) &p_field_value2);
    sip_free((void **) &p_content_body);
    frstr_free(&p_frstr);
    frreport_body_free(&p_st_body);
    sip_free((void **) &p_username);
    sip_free((void **) &p_uri);
    sip_free((void **) &p_uri_user);
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  解析SIP请求
*  ARGS     :  *p_st_conn                               (ct信息)
*           :  *p_st_sess                               (SIP私有的session)
*           :  *p_st_sip_packet                         (SIP数据包)
*           :  *p_st_hash_report                        (数据上报)
*  RTN      :  0                                        (FR_SUCC)
*              1                                        (FR_FAIL)
*  NOTE     :
*******************************************************************************/
int sip_analyze_req(Conntrack *p_st_conn
                    , L7session_sip *p_st_sess
                    , L7_sip_packet *p_st_sip_packet
                    , Frhash_header *p_st_hash_report
                    , Apm_packet *p_analyze_in)
{
    SIP_PRINT_FATAL("method:[%s]\n", p_st_sip_packet->p_req_method);
#if APM_SIP_DBG
    char arr_server_ip[56];
    snprintf(arr_server_ip, sizeof(arr_server_ip), "%s", int_ntoa(p_analyze_in->dst_ip));
    SIP_PRINT_ALERT("Server:[%s:%d]\n", arr_server_ip, p_analyze_in->dst_port);
#endif

    switch (p_st_sip_packet->em_req_method)
    {
        case SIP_METHOD_TYPE_INVITE:
            if (__sip_unpack_req(p_st_conn, p_st_sess, p_st_sip_packet, p_st_hash_report, p_analyze_in) != FR_SUCC)
                goto error;
            break;
        case SIP_METHOD_TYPE_ACK:
            if (__sip_unpack_req(p_st_conn, p_st_sess, p_st_sip_packet, p_st_hash_report, p_analyze_in) != FR_SUCC)
                goto error;
            break;
        case SIP_METHOD_TYPE_BYE:
            if (__sip_unpack_req(p_st_conn, p_st_sess, p_st_sip_packet, p_st_hash_report, p_analyze_in) != FR_SUCC)
                goto error;
            break;
        case SIP_METHOD_TYPE_CANCEL:
            if (__sip_unpack_req(p_st_conn, p_st_sess, p_st_sip_packet, p_st_hash_report, p_analyze_in) != FR_SUCC)
                goto error;
            break;
        case SIP_METHOD_TYPE_OPTIONS:
            if (__sip_unpack_req(p_st_conn, p_st_sess, p_st_sip_packet, p_st_hash_report, p_analyze_in) != FR_SUCC)
                goto error;
            break;
        case SIP_METHOD_TYPE_REGISTER:
            if (__sip_unpack_req(p_st_conn, p_st_sess, p_st_sip_packet, p_st_hash_report, p_analyze_in) != FR_SUCC)
                goto error;
            break;
        case SIP_METHOD_TYPE_INFO:
            if (__sip_unpack_req(p_st_conn, p_st_sess, p_st_sip_packet, p_st_hash_report, p_analyze_in) != FR_SUCC)
                goto error;
            break;
        case SIP_METHOD_TYPE_MESSAGE:
            if (__sip_unpack_req(p_st_conn, p_st_sess, p_st_sip_packet, p_st_hash_report, p_analyze_in) != FR_SUCC)
                goto error;
            break;
        case SIP_METHOD_TYPE_SUBSCRIBE: // 订阅
            if (__sip_unpack_req(p_st_conn, p_st_sess, p_st_sip_packet, p_st_hash_report, p_analyze_in) != FR_SUCC)
                goto error;
            break;
        case SIP_METHOD_TYPE_NOTIFY: // 通知
            if (__sip_unpack_req(p_st_conn, p_st_sess, p_st_sip_packet, p_st_hash_report, p_analyze_in) != FR_SUCC)
                goto error;
            break;
        default:
            ;
    }

    return FR_SUCC;
error:
    return FR_FAIL;
}
